<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BRTServiceBasicRoles
 * How to user this class:
 * 1.usually this class is used in sApp
 * 2.when use this class, first should set user/service/serviceApp if they are
 * not current one
 * 3.app can use this class to add roles and permits used by sApp by user addXXX functions
 * 4.finally can register to add roles into system and database
 * 5.some sApp can create own roletemplate with this class, in specific roletemplate
 * they must implement IBRoleTemplate interface to provide function for add permit
 * and assignrole
 * 6.can user importMeta function to import role template data in meta format
 *
 * @author Jianfeng
 */
final class BBasicRolesTemplate implements BIRoleTemplate {

    const WORKTEAM_ADMIN_ROLE = "workteam_admin";
    const WORKTEAM_MEMBER_ROLE = "workteam_member";
    const SERVEDTEAM_ADMIN_ROLE = 'servedteam_admin';
    const SERVEDTEAM_MEMBER_ROLE = 'servedteam_member';
    const SERVICE_MEMBER_ROLE = 'service_member';
    const SERVICE_ADMIN_ROLE = 'service_admin';
    const LOGIN_MEMBER_ROLE = 'login_member';
    const ROLE_TARGET_TYPE_USER = 'user_target';
    const ROLE_TARGET_TYPE_CIRCLE = "circle_target";
    const ROLE_RESOURCE_TYPE_OPERATION = "operation_resource";
    const LOGIN_MEMBER_ROLE_ID = -90001;

    private $serviceAdminChildren = null;
    private $workTeamAdminChildren = null;
    private $workTeamMemberChildren = null;
    private $serviceMemberChildren = null;
    private $servedTeamAdminChildren = null;
    private $servedTeamMemberChildren = null;
    private $activeService = null;
    private $activeApp = null;
    private $activeAppId = null;
    private $activeUer = null;
    private $roleMeta = array();
    private $basicRoleMeta = array(
        'service_admin' => array(
            'workteam_admin' => array(),
            'servedteam_admin' => array()
        ),
        'service_member' => array(
            'workteam_member' => array(),
            'servedteam_member' => array()
        )
    );

    public function __construct($appId = null) {

        if ($appId != null)
            $this->activeAppId = $appId;

        $this->roleMeta = $this->basicRoleMeta;
        //$this->activeApp = Blyn::app()->getActiveServiceApp();
        //$this->activeService = Blyn::app()->getActiveService();
        //$this->activeUser = Blyn::app()->getCurrentUser();
    }

    public function setServiceApp($app) {
        $this->activeApp = $app;
    }

    public function setService($service) {
        $this->activeService = $service;
    }

    public function setUser($user) {
        $this->activeUer = $user;
    }
    
    public function getAllBasicRoles()
    {
        $result = array();         

        BUtil::getRecursiveArrayKeys($this->basicRoleMeta, $result);
        
        return $result;
    }

    /**
     * serviceApp use this function to import roles meta from config file
     * it is called when register serviceApp
     * @param type $meta
     * format for meta file:
     * array(
     *  'admin'=>array(...),
     *  'member'=>array(...)
     *  )
     */
    public function importRolesByMeta($meta) {
        if (!is_array($meta))
            return FALSE;

        if ((isset($meta['admin']) && is_array($meta['admin'])) || (isset($meta[self::SERVICE_ADMIN_ROLE]) && is_array($meta[self::SERVICE_ADMIN_ROLE]))) {
            if (isset($meta['admin'])) {
                if (isset($meta['admin'][self::SERVICE_ADMIN_ROLE]))
                    $childRole = $meta['admin'][self::SERVICE_ADMIN_ROLE];
                else {
                    $childRole = $meta['admin'];
                }
            }
            if (isset($meta[self::SERVICE_ADMIN_ROLE]))
                $childRole = $meta[self::SERVICE_ADMIN_ROLE];

            $this->serviceAdminChildren = $childRole;

            $this->addChildRole($childRole, self::SERVICE_ADMIN_ROLE);
        }

        if ((isset($meta['member']) && is_array($meta['member'])) || (isset($meta[self::SERVICE_MEMBER_ROLE]) && is_array($meta[self::SERVICE_MEMBER_ROLE]))) {
            if (isset($meta['member'])) {
                if (isset($meta['member'][self::SERVICE_MEMBER_ROLE]))
                    $childRole = $meta['member'][self::SERVICE_MEMBER_ROLE];
                else {
                    $childRole = $meta['member'];
                }
            }
            if (isset($meta[self::SERVICE_MEMBER_ROLE]))
                $childRole = $meta[self::SERVICE_MEMBER_ROLE];

            $this->addChildRole($childRole, self::SERVICE_MEMBER_ROLE);
        }

        if (isset($meta[self::WORKTEAM_ADMIN_ROLE]) && is_array($meta[self::WORKTEAM_ADMIN_ROLE])) {
            $childRole = $meta[self::WORKTEAM_ADMIN_ROLE];
            $this->addChildRole($childRole, self::SERVICE_ADMIN_ROLE);
        }

        if (isset($meta[self::SERVEDTEAM_ADMIN_ROLE]) && is_array($meta[self::SERVEDTEAM_ADMIN_ROLE])) {
            $childRole = $meta[self::SERVEDTEAM_ADMIN_ROLE];
            $this->addChildRole($childRole, self::SERVEDTEAM_ADMIN_ROLE);
        }

        if (isset($meta[self::WORKTEAM_MEMBER_ROLE]) && is_array($meta[self::WORKTEAM_MEMBER_ROLE])) {
            $childRole = $meta[self::WORKTEAM_MEMBER_ROLE];
            $this->addChildRole($childRole, self::WORKTEAM_MEMBER_ROLE);
        }

        if (isset($meta[self::SERVEDTEAM_MEMBER_ROLE]) && is_array($meta[self::SERVEDTEAM_MEMBER_ROLE])) {
            $childRole = $meta[self::SERVEDTEAM_MEMBER_ROLE];
            $this->addChildRole($childRole, self::SERVEDTEAM_MEMBER_ROLE);
        }
    }

    public function addChildRole($childRole, $parentRole = NULL) {
        //add roles under admin into service_admin
        if ($parentRole == 'admin') {
            foreach ($childRole as $key => $role) {
                // if ($key != self::SERVICE_ADMIN_ROLE || $key != self::WORKTEAM_ADMIN_ROLE || $key != self::SERVEDTEAM_ADMIN_ROLE) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_ADMIN_ROLE]);
                //  }
            }
        }

        if ($parentRole == NULL || $parentRole == 'member') {
            foreach ($childRole as $key => $role) {
                //   if ($key != self::SERVICE_MEMBER_ROLE || $key != self::WORKTEAM_MEMBER_ROLE || $key != self::SERVEDTEAM_MEMBER_ROLE) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_MEMBER_ROLE]);
                //   }
            }
        }

        if ($parentRole == self::SERVICE_ADMIN_ROLE) {
            foreach ($childRole as $key => $role) {
                //   if ($key != self::WORKTEAM_ADMIN_ROLE || $key != self::SERVEDTEAM_ADMIN_ROLE) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_ADMIN_ROLE]);
                //    }
            }
        }

        if ($parentRole == self::SERVICE_MEMBER_ROLE) {
            foreach ($childRole as $key => $role) {
                //     if ($key != self::WORKTEAM_MEMBER_ROLE || $key != self::SERVEDTEAM_MEMBER_ROLE) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_MEMBER_ROLE]);
                //     }
            }
        }

        if ($parentRole == self::WORKTEAM_ADMIN_ROLE) {
            foreach ($childRole as $key => $role) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_ADMIN_ROLE][self::WORKTEAM_ADMIN_ROLE]);
            }
        }

        if ($parentRole == self::WORKTEAM_MEMBER_ROLE) {
            foreach ($childRole as $key => $role) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_MEMBER_ROLE][self::WORKTEAM_MEMBER_ROLE]);
            }
        }

        if ($parentRole == self::SERVEDTEAM_ADMIN_ROLE) {
            foreach ($childRole as $key => $role) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_ADMIN_ROLE][self::SERVEDTEAM_ADMIN_ROLE]);
            }
        }

        if ($parentRole == self::SERVEDTEAM_MEMBER_ROLE) {
            foreach ($childRole as $key => $role) {
                $this->addChildRoleWithName($key, $role, $this->roleMeta[self::SERVICE_MEMBER_ROLE][self::SERVEDTEAM_MEMBER_ROLE]);
            }
        }
    }

    private function addChildRoleWithName($roleName, $childRole, &$parentRole = array()) {
        $parentRole[$roleName] = $childRole;
    }

    public function assignRoles($roles, $target = null, $targetType = NULL) {
        $db = Blyn::app()->getAppDb();

        $service = $this->activeService;
        $sApp = $this->activeApp;

        if ($targetType == NULL) {
            $targetType == self::ROLE_TARGET_TYPE_USER;
        }

        $user = NULL;

        $metaRoles = array();

        $this->getRecursiveRoles($this->roleMeta, $metaRoles);

        if (is_string($roles))
            $roles = explode(',', $roles);

        foreach ($roles as $roleName) {

            if (in_array($roleName, $metaRoles)) {

                $roleId = $sApp->getDbAdapter()->getRoleId($sApp->getId(), $roleName);

                if ($targetType == self::ROLE_TARGET_TYPE_USER) {
                    $user = $target instanceof BUser ? $target : $this->activeUer;
                    $db->assignUserRole($service->getId(), $user->getId(), $roleId);
                }

                if ($targetType == self::ROLE_TARGET_TYPE_CIRCLE) {
                    $circle = $target instanceof BCircle ? $target : BCircle::getCircleByName($target);
                    $db->assignCircleRole($service->getId(), $circle->getId(), $roleId);
                }
            }
        }
    }

    public function addPermits($roles, $resource, $resourceType = NULL) {

        $sApp = $this->activeApp;

        $metaRoles = array();
        $this->getRecursiveRoles($this->roleMeta, $metaRoles);

        if ($resourceType == NULL)
            $resourceType == self::ROLE_RESOURCE_TYPE_OPERATION;

        if ($resourceType == self::ROLE_RESOURCE_TYPE_OPERATION) {
            if ($resource instanceof BOperation)
                $operationId = $resource->getId();
            else {
                $operationId = $this->getOperationIdByName($resource);
            }
        }

        $db = Blyn::app()->getAppDb();

        foreach ($roles as $roleName) {

            if (in_array($roleName, $metaRoles)) {

                $roleId = $sApp->getDbAdapter()->getRoleId($sApp->getId(), $roleName);
                $db->addOperationToRole($operationId, $roleId);
            }
        }
    }

    /**
     * register function is called when serviceApp register or update roles in serviceApp
     * @param type $config
     * @return type 
     */
    public function register($config = NULL) {

        $serviceEngineAppId = Blyn::app()->getAppDb()->getServiceAppId("BServiceEngine");

        $roleManager = new BAuthManager($this->activeAppId);

        //add roles of serviceEngine
        if ($this->activeAppId == $serviceEngineAppId) {
            $roleManager->createRecursiveRole2($this->basicRoleMeta);
            return;
        }

        //add child roles under service member
        if ($this->serviceMemberChildren != NULL) {
            foreach ($this->serviceMemberChildren as $roleName => $role) {
                $roleManager->createRecursiveRole2($role, self::SERVICE_MEMBER_ROLE);
                $db = Blyn::app()->getAppDb();
                $parentRole = $roleManager->getRole(self::SERVICE_MEMBER_ROLE, 'BServiceEngine');
                $childRole = $roleManager->getRole($roleName);
                $db->addChildRole($parentRole->getId(), $childRole->getId());
            }
        }

        if ($this->serviceAdminChildren != NULL) {
            foreach ($this->serviceAdminChildren as $roleName => $role) {
                $roleManager->createRecursiveRole2($role);
                $db = Blyn::app()->getAppDb();
                $parentRole = $roleManager->getRole(self::SERVICE_ADMIN_ROLE, 'BServiceEngine');
                $childRole = $roleManager->getRole($roleName);
                $db->addChildRole($parentRole->getId(), $childRole->getId());
            }
        }

        if ($this->workTeamAdminChildren != NULL) {
            foreach ($this->workTeamAdminChildren as $roleName => $role) {
                $roleManager->createRecursiveRole2($role);
                $db = Blyn::app()->getAppDb();
                $parentRole = $roleManager->getRole(self::WORKTEAM_ADMIN_ROLE, 'BServiceEngine');
                $childRole = $roleManager->getRole($roleName);
                $db->addChildRole($parentRole->getId(), $childRole->getId());
            }
        }

        if ($this->workTeamMemberChildren != NULL) {
            foreach ($this->workTeamMemberChildren as $roleName => $role) {
                $roleManager->createRecursiveRole2($role);
                $db = Blyn::app()->getAppDb();
                $parentRole = $roleManager->getRole(self::WORKTEAM_MEMBER_ROLE, 'BServiceEngine');
                $childRole = $roleManager->getRole($roleName);
                $db->addChildRole($parentRole->getId(), $childRole->getId());
            }
        }

        if ($this->servedTeamAdminChildren != NULL) {
            foreach ($this->servedTeamAdminChildren as $roleName => $role) {
                $roleManager->createRecursiveRole2($role);
                $db = Blyn::app()->getAppDb();
                $parentRole = $roleManager->getRole(self::SERVEDTEAM_ADMIN_ROLE, 'BServiceEngine');
                $childRole = $roleManager->getRole($roleName);
                $db->addChildRole($parentRole->getId(), $childRole->getId());
            }
        }

        if ($this->servedTeamMemberChildren != NULL) {
            foreach ($this->servedTeamMemberChildren as $roleName => $role) {
                $roleManager->createRecursiveRole2($role);
                $db = Blyn::app()->getAppDb();
                $parentRole = $roleManager->getRole(self::SERVEDTEAM_MEMBER_ROLE, 'BServiceEngine');
                $childRole = $roleManager->getRole($roleName);
                $db->addChildRole($parentRole->getId(), $childRole->getId());
            }
        }
    }

    private function getRecursiveRoles($roleMeta, &$roles = array()) {

        foreach ($roleMeta as $key => $value) {
            array_push($roles, $key);

            if (is_array($value))
                $this->getRecursiveRoles($value, $roles);
        }
    }

    private function getOperationIdByName($name) {
        $sApp = $this->activeApp;

        $opId = $sApp->getDbAdapter()->getOperationId($sApp->getId(), $name);

        return $opId;
    }

    public function checkAccess($roles, $user, $service, $sApp) {

        //$db = Blyn::app()->getAppDb();

        $metaRoles = array();

        $this->getUserRecursiveRoles($user, $service, $sApp);

        if (is_string($roles))
            $roles = explode(',', $roles);

        foreach ($roles as $roleName) {

            if (in_array($roleName, $metaRoles)) {
                return TRUE;
            }
        }

        return FALSE;
    }

}

?>
